home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / misc / math / gpamiga_1_38_3.lha / elisp / pari.el < prev    next >
Encoding:
Text File  |  1993-12-09  |  25.4 KB  |  753 lines

  1. ;; This is the interface for pari under emacs
  2. ;; The main commands in this file are
  3. ;; M-x gp      Opens a buffer for interaction with gp and then starts gp.
  4. ;; C-u M-x gp  Like M-x gp, but prompts for command line arguments.
  5. ;; M-x gpman   Displays the gp-pari manual using any dvi preview program.
  6.  
  7. ;; All functions of gp are preserved.
  8.  
  9. ;; This version by David Carlisle (JANET: carlisle@uk.ac.man.cs).
  10. ;; The original pari.el was written by Annette Hoffman.
  11.  
  12.  
  13. ;; Version 2.13 (06-July-1993)
  14.  
  15. ;; See  pari.txt  for more details.
  16.  
  17.  
  18. (provide 'gp)
  19.  
  20. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  21.  
  22. ;; The following five constants (aka variables !) should be
  23. ;; set for each site.
  24.  
  25. (defconst gp-chap3 "pari:doc/usersch3.tex"
  26. ;;(defconst gp-chap3 "~pari/PARI/doc/usersch3.tex"
  27.   "The TeX source for chapter 3 of the PARI-GP manual")
  28.  
  29. (defconst gp-file-name "pari:bin/gp.68881"
  30. ;;(defconst gp-file-name "/usr/local/bin/gp"
  31.   "The file name of the gp executable file")
  32.  
  33. (defconst gp-man-dvi "pari:doc/users.dvi" 
  34. ;;(defconst gp-man-dvi "~pari/PARI/SPARCV8/doc/users.dvi" 
  35.  "dvi version of the manual")
  36.  
  37. (defconst  gp-menu "pari:elisp/pari.menu"
  38. ;;(defconst  gp-menu "~pari/PARI/pari.menu"
  39.    "menu file")
  40.  
  41. (defconst gp-dvi-preview "xdvi -s 3"
  42. ;; (defconst gp-dvi-preview "texsun"
  43.   "dvi previewer (and options)")
  44.  
  45. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  46.  
  47. ;; Individual users may want to re-set some of the variables in this section
  48. ;; in a gp-mode-hook in their .emacs file.
  49.  
  50. ;; See pari.txt for an example of a gp-mode-hook.
  51.  
  52. (defvar gp-stack-size "1000000"
  53. ;;(defvar gp-stack-size "4000000"
  54.   "Default stack size: passed to the progam gp.")
  55.  
  56. (defvar gp-buffer-size "30000"
  57.   "Default buffer size: passed to the progam gp.")
  58.  
  59. (defvar gp-prime-limit "500000"
  60.   "Default prime limit: passed to the progam gp.")
  61.  
  62. (defvar gp-prompt-for-args nil
  63.   "A non-nil value makes M-x gp act like C-u M-x gp, 
  64.    ie prompt for the command line arguments.")
  65.  
  66. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  67.  
  68. (setq gp-temp-file (make-temp-name "t:gp_"))
  69. ;;(setq gp-temp-file (make-temp-name "/usr/tmp/gp_"))
  70.  
  71. (defvar gp-prompt-pattern
  72.   "---- (type return to continue) ----\\|\\?[\C-j\t ]*"
  73.   "Regexp used to match gp prompts.
  74.    can be set with gp-set-prompt (bound to M-\\ p)")
  75.  
  76. (defconst gp-c-array (make-vector 509 0)
  77.   "obarray used fo completing gp command names")
  78.  
  79.  
  80. (defvar gp-map (make-sparse-keymap)
  81.   "Local keymap used in buffer *PARI*.")
  82.  
  83. (define-key gp-map "\C-m"    'gp-send-input)
  84. (define-key gp-map "\M-\C-m" 'gp-copy-input)
  85. (define-key gp-map "\M-\t"   'gp-complete)
  86. (define-key gp-map "\M-\\p"  'gp-set-prompt)
  87. (define-key gp-map "\M-\\t"  'gp-meta-t)
  88. (define-key gp-map "\M-\\d"  'gp-meta-d)
  89.  
  90. (define-key gp-map "\M-\\r"  'gp-meta-r)
  91. (define-key gp-map "\M-\\w"  'gp-meta-w)
  92. (define-key gp-map "\M-\\v"  'gp-meta-v)
  93. (define-key gp-map "\M-\\x"  'gp-meta-x)
  94. (define-key gp-map "\M-\\s"  'gp-meta-s)
  95. (define-key gp-map "\M-\\a"  'gp-meta-a)
  96. (define-key gp-map "\M-\\b"  'gp-meta-b)
  97. (define-key gp-map "\M-\\m"  'gp-meta-m)
  98. (define-key gp-map "\M-\\k"  'gp-meta-k)
  99. (define-key gp-map "\M-\\q"  'gp-meta-q)
  100. (define-key gp-map "\M-?"    'gp-get-man-entry)
  101. (define-key gp-map "\M-\\c"  'gp-menu)    
  102. (define-key gp-map "\M-\\\\"  'gp-break-long-line)
  103. (define-key gp-map "\C-c"    'gp-interrupt)
  104.  
  105. (defvar gp-process nil "")
  106. (defvar gp-man-process nil "")
  107.  
  108. (defun gp (flag)
  109.   "
  110.    Open a buffer and a window for the execution of gp.
  111.  
  112.    The following bindings are available:
  113.    \\{gp-map}
  114.  
  115.   The variables
  116.   gp-file-name gp-stack-size gp-buffer-size gp-prime-limit
  117.   determine the command line that starts gp.
  118.   To override the default settings, give gp a prefix argument.
  119.   C-u M-x gp ."
  120.   (interactive "P")
  121. ;; Create buffer *PARI* and make it become the current buffer.
  122.   (switch-to-buffer "*PARI*") 
  123.   (goto-char (point-max))
  124.   (if (and (processp gp-process) 
  125.            (eq (intern "run") (process-status gp-process)))
  126. ;; If gp is already running, do  nothing.
  127.     nil
  128. ;; Else start up gp in the buffer.
  129.     (kill-all-local-variables)
  130.     (setq major-mode 'gp)
  131.     (setq mode-name "GP")
  132. ;; Set up user preferences.
  133.     (run-hooks 'gp-mode-hook)
  134.  
  135. ;; Make gp-map the local map of buffer *PARI*.
  136.     (use-local-map gp-map)      
  137.     (setq mode-line-process '(": %s"))
  138.  
  139. ;; Now we can make the default completion array, must be here, as
  140. ;; gp-menu may be set in the user's hook.
  141.     (gp-completion-file gp-menu)
  142.  
  143. ;; Form the command line string.
  144.     (let* (
  145.       (flag (or flag gp-prompt-for-args))
  146.       (gp-command
  147.       (concat
  148.         (gp-read-input "Gp executable ?" gp-file-name "" flag)
  149.         (gp-read-input "Stack size ?" gp-stack-size " -s " flag)
  150.         (gp-read-input "Buffer size ?" gp-buffer-size " -b " flag)
  151.         (gp-read-input "Prime limit ?" gp-prime-limit " -p " flag))))
  152. ;; Insert the command line string into the *PARI* buffer.
  153. ;; (This is just for reference.)
  154.       (insert (concat "\n" gp-command "\n"))
  155. ;; Start gp.
  156.       (let ((gp-begin (point)))
  157.         (setq gp-process
  158.           (start-process 
  159.             "pari" "*PARI*" shell-file-name "-c" 
  160.               (concat "stty nl; exec " gp-command)))
  161. ;; Get the version number from the banner.
  162.         (gp-wait-for-output)
  163.         (save-excursion
  164.         (re-search-backward "Version  *\\([.0-9]*\\)" gp-begin)
  165.         (setq gp-version (buffer-substring (match-beginning 1) (match-end 1))))))
  166. ;; Clean up when the gp process has finished.
  167.       (set-process-sentinel gp-process  'gp-sentinel)))
  168.  
  169. (defun gp-read-input (prompt default sep flag)
  170. " If flag is non-nil, reads string then if string is \"\" uses default.
  171.   If flag is nil then string is the default.
  172.   If resulting string is not \"\" prepends sep.
  173.   As a special case, if string is a space, return \"\"."
  174.   (let ((string 
  175.     (if flag
  176. ;; If flag is non-nil prompt for input from mini-buffer.
  177.       (read-input 
  178.         (concat prompt " (Default "default") "))
  179. ;; Else use the default string.
  180.         default)))
  181.     (if (equal string "")
  182.       (if (equal default "") 
  183. ;; If sting and default both "": 
  184.          ""
  185. ;; If string "" and default is non empty:
  186.          (concat sep default))
  187.       (if (equal string " ")
  188. ;; If string is a space:
  189.         ""
  190. ;; If string is non empty:
  191.         (concat sep string)))))
  192.  
  193. (defun gp-sentinel (proc msg)
  194.   "Sentinel for the gp-process in buffer *PARI*."
  195.     (if (get-buffer "*gp-help*") (kill-buffer "*gp-help*"))
  196.     (let ((b (get-file-buffer gp-chap3))) (if b (kill-buffer b)))
  197.     (let ((b (get-file-buffer gp-menu)))  (if b (kill-buffer b)))
  198.     (if (get-buffer "*PARI*")
  199.       (progn
  200.         (set-buffer "*PARI*")
  201.         (goto-char (point-max))
  202.         (insert msg)
  203.         (delete-windows-on "*PARI*")))
  204.     (if (file-exists-p gp-temp-file) 
  205.        (progn (delete-file gp-temp-file) 
  206.               (message "Removing %s" gp-temp-file )))
  207.   (setq gp-process nil))
  208.  
  209. (defun gpman()
  210.   "Start up xdvi with the gp manual."
  211.   (interactive)
  212. ;; Run gp-mode-hook in case it specifies a different
  213. ;; version of the manual.
  214.   (run-hooks 'gp-mode-hook)
  215.   (set-buffer (get-buffer-create "*GP-MAN*"))
  216.   (if gp-man-process
  217.      nil
  218. ;; Start xdvi.
  219.     (message (concat "Starting " gp-dvi-preview " " gp-man-dvi))
  220.     (setq gp-man-process
  221.       (start-process "gp-man" "*GP-MAN*"
  222.           shell-file-name
  223.           "-c" (concat "exec " gp-dvi-preview " " gp-man-dvi)))
  224.     (set-process-sentinel gp-man-process 'gp-man-sentinel)))
  225.  
  226. (defun gp-man-sentinel (proc msg)
  227.   "Sentinel for the gp-man-process in buffer *GP-MAN*."
  228.   (let ((buf (process-buffer proc)))
  229.     (if buf (kill-buffer buf)))
  230.   (message (concat "gpman: " msg))
  231.   (setq gp-man-process nil))
  232.  
  233. (defun gp-copy-input()
  234.   "Copy expression around point to the end of the buffer.
  235.    (Unless this is already the last expression.)"
  236.   (interactive)
  237. ;; Go back to the end of prompt, and record that point.
  238. ;; If a line contains more than one prompt string, use the FIRST.
  239. ;; This is so that ? ?cos works. (ie gives the help for cos).
  240. ;; We can not insist on prompt at the beginning of a line (ie put
  241. ;; ^ in gp-prompt-pattern) because of the output from print1()
  242.   (re-search-backward gp-prompt-pattern)
  243.   (let ((p (match-end 0)))
  244.     (beginning-of-line)
  245.     (re-search-forward gp-prompt-pattern)
  246.     (setq gp-input-start (point))
  247. ;; Go past the last prompt on this line before looking for end of expression.
  248.     (goto-char p))
  249. ;; Check if we are already at the last expression.
  250.   (let ((nlast (re-search-forward (concat "[\n ]*\\("
  251.        gp-prompt-pattern
  252.        "\\|^%[0-9]+ = \\|^ *\\*\\*\\*\\|^ *unused characters\\|^ *time[ r]\\)")
  253.              (point-max) t)))
  254. ;; Find the limit of the expression.
  255. ;;   This is the end of buffer, the prompt, or an error message.
  256.   (let ((limit (if nlast (match-beginning 0) (point-max))))
  257.   (goto-char gp-input-start)
  258. ;; End of expression is a line ending with } if it starts with {,
  259. ;;   otherwise a line not ending with \.
  260.   (let ((end-expression (if (looking-at " *{") "}$" "[^\\]$")))
  261. ;; Look for the end of expression, as far as the limit computed above.
  262.   (setq gp-complete-expression  (re-search-forward end-expression limit 1))
  263.   (setq gp-input-end (point))
  264. ;; If not already the last expression copy to the end of the buffer.
  265.   (if nlast 
  266.    (progn
  267.      (goto-char (point-max))
  268.      (insert (buffer-substring gp-input-start gp-input-end))
  269.      (if gp-complete-expression
  270.        nil
  271.        (ding)
  272.        (message "Incomplete expression."))))))))
  273.  
  274. (defun gp-send-input ()
  275.   "Send input to gp. Does not send incomplete expressions
  276.    ie those starting with {, without a matching }, or those
  277.    ending with \\ .
  278.    Use a temporary file (and \\r ) for large expressions"
  279.   (interactive)
  280. ;; gp-copy-input does all the work!
  281.   (gp-copy-input)
  282.   (insert "\n")
  283.   (if gp-complete-expression
  284. ;; If it is a complete expression do this:
  285.     (progn
  286.       (if (> (- gp-input-end gp-input-start) 255)
  287. ;; If large expression, use a temporary file.
  288.         (progn 
  289.           (write-region gp-input-start gp-input-end gp-temp-file)
  290.           (process-send-string gp-process (concat "\\r "gp-temp-file"\n")))
  291. ;; Else use process-send-region.
  292.         (process-send-region gp-process gp-input-start gp-input-end)
  293.         (process-send-string gp-process "\n"))
  294.       (set-marker (process-mark gp-process) (point)))
  295. ;; Else do this:
  296.     (message "Incomplete expression: Not sent to gp.")))
  297.  
  298. (defun gp-interrupt ()
  299.   "Interrupt gp.
  300.    This is identical to interrupt-shell-subjob in shell-mode."
  301.   (interactive)
  302.   (interrupt-process nil t))
  303.  
  304. (defun gp-set-prompt (p)
  305.   "Set new gp prompt (and tell emacs that you have done so).
  306.    Do not put spaces in the argument, or emacs and gp will
  307.    have a different idea about what the prompt is."
  308.   (interactive "sNew prompt: ")
  309. ;; gp-prompt-pattern matches:
  310. ;; (New prompt plus any following white space) OR (Old pattern).
  311.   (setq gp-prompt-pattern 
  312.     (concat (regexp-quote p) "[\C-j\t ]*\\|" gp-prompt-pattern))
  313.   (set-buffer "*PARI*")
  314.   (goto-char (point-max))
  315. ;; Tell gp about the change too!
  316.   (insert (concat "\\prompt="p))
  317.   (gp-send-input))
  318.  
  319. (defun gp-replace (a b)
  320.   "Replace the regexp a by the string b everywhere in the current buffer"
  321.   (goto-char (point-min))
  322.   (while (re-search-forward a (point-max) t)
  323.     (replace-match b t t)))
  324.  
  325. (defun gp-get-man-entry (fn)
  326.   "Obtains the description of fn from chapter 3 of the manual.
  327.   Strips off some (not all) of the TeX syntax, and displays the result
  328.   in a new window.
  329.   If there is no entry for fn in the manual, sends ?fn to gp.
  330.   If a definition for fn is found, adds fn to the array of possible
  331.   completions"
  332.   (interactive
  333.     (list  (let* (
  334.              (word 
  335. ;; get the word before point into word
  336.               (save-excursion
  337.                  (forward-word -1)
  338.                  (downcase (buffer-substring (point) 
  339.                    (progn  (forward-word 1) (point))))))
  340. ;; get the argument from the minibuffer
  341.              (arg
  342.                (completing-read 
  343.                  (concat "Function" 
  344.                    (if (intern-soft word gp-c-array)
  345. ;; If the word before point is a gp function, offer it as default.
  346.                      (concat " (Default " word ")" )) ": ")
  347. ;; use gp-c-array as the completion array
  348.                   gp-c-array)))
  349.       (if (equal arg "")
  350. ;; If the argument supplied is "", and word is a gp symbol, use it as default.
  351. ;; (Do not use "" as fn in anycase, so otherwise use " ", which will not
  352. ;; produce a help window.)
  353.         (if (intern-soft word gp-c-array) word " ") 
  354. ;; Else use the arg.
  355.         arg))))
  356. ;; end of interactive call
  357. ;; Stop TeX-mode being loaded for gp-chap3.
  358.   (let ((auto-mode-alist nil))
  359.     (set-buffer (find-file-noselect gp-chap3)))
  360. ;; Fix up one or two special cases, or 
  361. ;; regexp-quote the argument.
  362.   (let ((qfn (cond
  363.            ((equal fn "\\" ) "\\\\backslash")
  364.            ((equal fn "^" ) "\\\\hat{}")
  365.            ((equal fn "!" ) "fact")
  366.            ((equal fn "~" ) "trans") 
  367.            ((equal fn "_" ) "conj")
  368.            ((equal fn "-" ) "\\+")
  369.            ((equal fn "%" ) "\\\\%")
  370.            ((equal fn "min" ) "max")
  371.            ((equal fn "log" ) "ln")
  372.            ((equal fn "det2" ) "det")
  373.            ((or (equal fn "<=" )(equal fn "<" )(equal fn ">=" )
  374.             (equal fn ">" )(equal fn "==" )(equal fn "!=" )
  375.             (equal fn "||" )(equal fn "&&" )) 
  376.                       "comparison and \\\\ref{boolean operators}")
  377.            ((regexp-quote fn)))))
  378. ;; Find the entry.
  379.   (goto-char (point-min))
  380. ;; Entry starts with \subsec ... fn
  381.   (if (re-search-forward 
  382.      (concat "\\(subsec[\\\\{ref]*[\\${]\\)" qfn "[}\\$]") (point-max) t)
  383. ;; If There is an entry in the manual do this:
  384.   (progn
  385.     (goto-char (match-end 1))
  386.     (let ((copy (buffer-substring (point) 
  387. ;; Entry ends with "The library" or the next (sub-)section.
  388.           (progn (re-search-forward "[tT]he library\\|\\\\[sub]*sec" 
  389.                     (point-max) t) 
  390.                  (match-beginning 0))))
  391.           (wind (selected-window)))
  392. ;; Copy the entry to the help buffer.
  393.     (switch-to-buffer-other-window (get-buffer-create "*gp-help*"))
  394.     (erase-buffer)
  395.     (insert copy)
  396. ;; Strip off some of the TeX. Note the idea is to leave enough
  397. ;; pseudo-TeX so that the entry is understandable. Thus want to
  398. ;; leave:  a^2,  x \over y, etc.
  399.     (gp-replace "\\$-" "-")
  400.     (gp-replace "\\$" " " )
  401.     (gp-replace "\\\\backslash" "\\")
  402.     (gp-replace "\\\\hat" "^")
  403.     (gp-replace "\\\\vers" gp-version)
  404.     (gp-replace
  405. "\\\\smallskip\\|\\\\sref{[ a-z]*}\\|\\\\bf\\|\
  406. \\\\ref\\|\\\\Bbb\\|\\\\text\\|\\\\tt\\|{\\|}"
  407.       "")
  408.     (goto-char (point-min))
  409.     (select-window wind)))
  410. ;; Else there is no entry in the manual. So send ?fn to gp.
  411.   (set-buffer "*PARI*")
  412. ;;; (downcase fn) as ?COS does not work gp bug ??
  413.   (gp-meta-command (concat "?" (downcase fn)))))
  414. ;; Addition at version 2.10
  415. ;; If the result is a gp function make sure that it is in the
  416. ;; completion array.
  417.   (set-buffer "*gp-help*")
  418.   (if (looking-at "Unknown function")
  419. ;; If the fuction is not known hide the help window.
  420.        (progn (bury-buffer (get-buffer "*gp-help*"))
  421.               (delete-windows-on "*gp-help*") 
  422.               (message "Unknown function: %s" fn))
  423. ;; Else let the completion system know about the fuction name.
  424.        (gp-add-symbol fn)))
  425.  
  426. (defun gp-meta-command (command)
  427.   "Send command to gp, and display output in help buffer"
  428.   (save-excursion
  429.   (goto-char (point-max))
  430. ;; Make sure that gp sends the text to the end of the buffer, so we
  431. ;; can move it  to the help buffer.
  432.   (set-marker (process-mark gp-process) (point))
  433.   (let ((temp (point)) (wind (selected-window)))
  434. ;; Send the meta command to gp.
  435.   (process-send-string gp-process (concat command "\n"))
  436. ;; Wait for the gp-prompt to be sent.
  437.   (gp-wait-for-output)
  438. ;; Display the output in the help buffer.
  439.   (let ((copy (buffer-substring temp (point-max))))
  440.   (delete-region temp (point-max))
  441.   (switch-to-buffer-other-window (get-buffer-create "*gp-help*"))
  442.   (erase-buffer)
  443.   (insert copy)
  444.   (beginning-of-line)
  445.   (delete-region (point) (point-max))
  446.   (goto-char (point-min))
  447.   (select-window wind)))))
  448.  
  449. (defun gp-wait-for-output ()
  450.   "Hang around until the prompt appears."
  451.   (let ((ndone t))
  452.   (while ndone 
  453.   (accept-process-output gp-process)
  454.   (let ((p (point))) 
  455.     (beginning-of-line)
  456.     (if (or (not (and (processp gp-process) 
  457.              (eq 'run (process-status gp-process))))
  458.              (looking-at gp-prompt-pattern))
  459. ;; If gp is not running, or the prompt has appeared, stop.
  460.       (progn (message "done") (setq ndone nil))
  461. ;; Else wait a bit longer.
  462.       (message "Waiting for gp output ..."))
  463.     (goto-char p)))))
  464.  
  465. (defun gp-meta-d ()
  466.   "Sends \\d to gp, then displays output in the help buffer.
  467.   Prints the gp defaults."
  468.   (interactive)
  469.   (gp-meta-command "\\d"))
  470.  
  471. (defun gp-meta-t ()
  472.   "Sends \\t to gp, then displays output in the help buffer.
  473.   Prints the longword format of PARI types."
  474.   (interactive)
  475.   (gp-meta-command "\\t"))
  476.  
  477. (defun gp-meta-r (file)
  478.   "Sends a \\r <file name> comand to gp.
  479.    Reads in gp commands from a file."
  480.   (interactive "fRead from file: ")
  481.   (goto-char (point-max))
  482.   (insert (concat "\\r " (expand-file-name file)))
  483.   (gp-send-input))
  484.  
  485. (defun gp-meta-w (file num)
  486.   "Sends a \\w<num> <file name> comand to gp.
  487.   Writes gp object %<num> to <file name>."
  488.   (interactive "FWrite to file: \nsObject number %%")
  489.   (goto-char (point-max))
  490.   (insert (concat "\\w"num" " (expand-file-name file)))
  491.   (gp-send-input))
  492.  
  493. (defun gp-meta-x ()
  494.   "Sends \\x to gp, then displays output in the help buffer.
  495.   Prints tree of addresses and contents of last object."
  496.   (interactive)
  497.   (gp-meta-command "\\x"))
  498.  
  499. (defun gp-meta-v ()
  500.   "Sends \\v to gp, then displays output in the help buffer.
  501.   Prints the version number of this implementation of pari-gp."
  502.   (interactive)
  503.   (gp-meta-command "\\v"))
  504.  
  505. (defun gp-meta-s (num)
  506.   "Sends \\s or \\s(num) to gp, then displays output in the help buffer.
  507.   Prints the state of the pari stack."
  508.   (interactive "sNumber of longwords (default 0) ")
  509.   (if (equal num "")
  510.     (gp-meta-command "\\s")
  511.     (gp-meta-command (concat "\\s(" num ")" ))))
  512.  
  513. (defun gp-meta-a (num)
  514.   "Sends \\a or \\a<num> to gp, then displays output in the help buffer.
  515.   Prints object %<num> in raw format."
  516.   (interactive "sPrint object (default last) %%")
  517.   (if (equal num "")
  518.     (gp-meta-command "\\a")
  519.     (gp-meta-command (concat "\\a" num))))
  520.  
  521. (defun gp-meta-b (num)
  522.   "Sends \\b or \\b<num> to gp, then displays output in the help buffer.
  523.   Prints object %<num> in pretty format."
  524.   (interactive "sPrint object (default last) %%")
  525.   (if (equal num "")
  526.     (gp-meta-command "\\b")
  527.     (gp-meta-command (concat "\\b" num))))
  528.  
  529. (defun gp-meta-m (num)
  530.   "Sends \\m or \\m<num> to gp, then displays output in the help buffer.
  531.   Prints object %<num> in prettymatrix format."
  532.   (interactive "sPrint object (default last) %%")
  533.   (if (equal num "")
  534.     (gp-meta-command "\\m")
  535.     (gp-meta-command (concat "\\m" num))))
  536.  
  537. (defun gp-meta-k ()
  538.   "Sends \\k to gp.
  539.   Prompts for confirmation before 
  540.   re-initialising gp and clearing the buffer."
  541.   (interactive) 
  542.   (if (y-or-n-p "Re-initialise gp ? ") 
  543.     (progn
  544.       (set-buffer "*PARI*")
  545.       (goto-char (point-max))
  546.       (insert "\\k\n")
  547.       (set-marker (process-mark gp-process) (point))
  548.       (if (y-or-n-p "Clear *PARI* buffer ? ")
  549.          (erase-buffer))
  550.      (process-send-string gp-process "\\k\n")))
  551.   (message ""))
  552.  
  553. (defun gp-meta-q ()
  554.   "Sends \\q to gp.
  555.   Prompts for confirmation before quiting."
  556.   (interactive) 
  557.   (if (y-or-n-p "Quit gp ? ") 
  558.     (progn
  559.      (set-buffer "*PARI*")
  560.      (goto-char (point-max))
  561.      (process-send-string gp-process "\\q\n")))
  562.   (message ""))
  563.  
  564. (defun gp-break-long-line ()
  565.   "gp will not accept lines longer than 256.
  566.    gp-break-long-line breaks current line 
  567.    inserting \\ every (screen-width)-5 chars."
  568.   (interactive)
  569.   (let ((length (min (- (screen-width) 5) 250)))
  570.   (move-to-column length)
  571.   (while (not (looking-at "$"))
  572.     (insert "\\\n")
  573.     (move-to-column length))))
  574.  
  575. ;;; gp completion functions.
  576.  
  577. (defun gp-completion-file (file)
  578.   "Takes a file in the format of pari.menu, and adds all the commands
  579.   listed  to the obarray used for completion. If used interactively,
  580.   prompts for the filename in the minibuffer
  581.   The file must have at least one comment line, starting with #, All
  582.   lines before the first comment line are IGNORED."
  583.   (interactive "fFile of command names: ")
  584.   (save-excursion
  585.     (set-buffer (find-file-noselect file))
  586.     (goto-char (point-min))
  587.     (re-search-forward "#")
  588.     (while (not (eobp))
  589.       (forward-line 1)
  590.       (if (looking-at "#")
  591.         nil
  592. ;; else
  593.        (gp-add-symbol (buffer-substring
  594.        (point)
  595.        (progn (end-of-line) (point))))))))
  596.  
  597. (defun gp-completion-list (&rest args)
  598.   "The arguments are taken as a list of strings, each string is stored
  599.   as a symbol in the obarray used for completion.
  600.   So (gp-completion-list \"foo\" \"bar\" \"baz\") in the gp-mode-hook will
  601.   let the completion functions 'know' these commands."
  602.   (mapcar 'gp-add-symbol args))
  603.  
  604. (defun gp-add-symbol  (name)
  605.   "Add a name to the obarray"
  606.   (make-symbol name)
  607.   (intern (downcase name) gp-c-array))
  608.  
  609. (defun gp-complete ( )
  610.   "Attempts to complete a partially typed command in the *PARI*
  611.   buffer. Displays possible completions in the help buffer if no
  612.   unique completion can be done."
  613.   (interactive)
  614.   (if (not(= (preceding-char) ?\\ )) (forward-word -1))
  615.   (if (= (preceding-char) ?\\ ) (forward-char -1))
  616.     (let* ((c-begin (point))
  617.           (word (downcase (buffer-substring c-begin 
  618.                   (progn   (forward-word 1) (point)))))
  619.           (comp (try-completion word gp-c-array)))
  620. ;; The 3 possible outcomes of completion:
  621.      (cond 
  622. ;; (1)   Already complete.
  623.         ((eq comp t) (if (get-buffer "*gp-help*") 
  624.                         (delete-windows-on "*gp-help*"))
  625.                       (message "%s is complete" word))
  626. ;; (2)   Not found. (It may be a valid gp function, unknown to the
  627. ;;      completion system)
  628.         ((eq comp nil) (message "No Match found"))
  629. ;; (3)  Some extension to the word possible.
  630.         (t
  631.           (if (not(string= comp word))
  632. ;;     Add any unique extension to the *PARI* buffer.
  633.  
  634.            (progn (insert comp) 
  635.            (delete-region (+ c-begin (length word)) 
  636.              (+ c-begin (* 2(length word))))))
  637.           (if (eq t (try-completion comp gp-c-array))
  638. ;;     If the extended word is definitely complete, remove the help window
  639.              (progn 
  640.                (if (get-buffer "*gp-help*") (delete-windows-on "*gp-help*"))
  641.                (message "%s is complete" comp))
  642. ;;     else display all possible completions.
  643.           (with-output-to-temp-buffer "*gp-help*"
  644.            (display-completion-list (all-completions word gp-c-array ))))))))
  645.  
  646. ;; Do not do completion on \prompt, as the user is not supposed to
  647. ;; change the prompt, except via M-\ p
  648. (gp-completion-list "\\precision" "\\serieslength" "\\format")
  649.  
  650. ;;; The gp help mode.
  651.  
  652. (defun gp-menu ()
  653.   "Major-mode for the gp menu buffer.
  654. The available commands are
  655. \\{gp-menu-map}"
  656.   (interactive)
  657.   (find-file-other-window gp-menu)
  658.   (setq buffer-read-only t)
  659.   (kill-all-local-variables)
  660.   (setq major-mode 'gp-menu)
  661.   (setq mode-name "GP MENU")
  662.   (use-local-map gp-menu-map)
  663.   (gp-menu-main))
  664.  
  665. (defun gp-menu-info ()
  666.   (message "SPC=next DEL=previous RET=select m=main-menu q=quit s=scroll-help"))
  667.  
  668. (defun gp-menu-next ()
  669.   "Move down one line of the gp help menu. (Go to top if at the end.)"
  670.   (interactive)
  671.   (gp-menu-info)
  672.   (forward-line 1)
  673.   (if (eobp) 
  674.     (progn (ding) (goto-char (point-min)))))
  675.  
  676. (defun gp-menu-previous ()
  677.   "Move up one line of the gp help menu. (Go to bottom if at the top.)"
  678.   (interactive)
  679.   (gp-menu-info)
  680.   (if (bobp) 
  681.     (progn (ding) (goto-char (point-max)) (beginning-of-line)) 
  682.     (forward-line -1)))
  683.  
  684. (defun gp-menu-quit ()
  685.   "Switch the *PARI* buffer if it exists, or (other-buffer) if it does not."
  686.   (interactive)
  687.   (let ((w (get-buffer-window "*PARI*"))
  688.         (b (get-buffer "*PARI*")) )
  689.     (cond
  690.      (w (progn (delete-window)(select-window w)))
  691.      (b (switch-to-buffer b))
  692.      (t (switch-to-buffer (other-buffer))))))
  693.  
  694. (defun gp-menu-select ()
  695.   "Select a subject from the main menu, or a manual entry from a subject menu."
  696.   (interactive)
  697.   (if main-menu 
  698. ;; RET in main menu.
  699.     (progn
  700.       (setq main-menu nil)
  701.       (widen)
  702.       (beginning-of-line)
  703.       (let ((sect (buffer-substring 
  704.            (point) (progn (end-of-line) (point)))))
  705.          (narrow-to-region
  706.            (progn 
  707.              (re-search-forward (concat "^###" sect))
  708.              (forward-line 1) (point))
  709.            (progn (re-search-forward "\C-j###" ) (match-beginning 0))))
  710.       (goto-char (point-min)))
  711. ;; RET in subject menu.
  712.     (beginning-of-line)
  713.     (gp-get-man-entry (buffer-substring
  714.       (point)
  715.       (progn (end-of-line) (point)))))
  716.   (gp-menu-info))
  717.  
  718. (defun gp-menu-main ()
  719.   "Display the main menu."
  720.   (interactive)
  721.   (gp-menu-info)
  722.   (widen)
  723.   (goto-char (point-min))
  724.   (narrow-to-region (point)
  725.     (progn (re-search-forward "\C-j###") (match-beginning 0)))
  726.   (goto-char (point-min))
  727.   (setq done nil)
  728.   (setq main-menu t))
  729.  
  730. (defun gp-menu-scroll ()
  731.   "Scroll the gp help window if it is visible"
  732.   (interactive)
  733.   (gp-menu-info)
  734.   (if (get-buffer-window "*gp-help*") 
  735.     (let ((wind (selected-window)))
  736.       (switch-to-buffer-other-window  "*gp-help*")
  737.       (if (pos-visible-in-window-p (point-max))
  738.          (goto-char (point-min))
  739.          (scroll-up))
  740.       (select-window wind))))
  741.      
  742.  
  743. (defvar gp-menu-map (make-sparse-keymap)
  744.   "Local keymap used in gp menu buffer.")
  745.       
  746. (define-key gp-menu-map " "    'gp-menu-next)
  747. (define-key gp-menu-map "\C-?" 'gp-menu-previous)
  748. (define-key gp-menu-map "\C-m" 'gp-menu-select)
  749. (define-key gp-menu-map "q"    'gp-menu-quit)
  750. (define-key gp-menu-map "m"    'gp-menu-main)
  751. (define-key gp-menu-map "s"    'gp-menu-scroll)
  752.  
  753.